package com.happyelements.display.rendering
{
	import com.happyelements.cache.AnimationCache;
	import com.happyelements.cache.AnimationCacheManager;
	import com.happyelements.cache.data.FrameInfo;
	import com.happyelements.display.constants.AnimationRendererStatus;
	
	import flash.display.BitmapData;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	/**
	 *
	 * @author Steven
	 *
	 */
	public class AnimationRenderer implements IRenderer
	{
		private static const TOTAL_FRAMES_UNAVAILABLE:int = -1;
		
		private static const __PAINT_DECT_POINT:Point = new Point();
		
		public var status:uint;
		
		private var _url:String; 
		
		private var _animationClass:String; 
		
		private var _cacheStrategy:uint;
		
		private var _cache:AnimationCache;
		
		private var _action:String;
		
		private var _currentFrame:int;
		
		private var __totalFrames:int = TOTAL_FRAMES_UNAVAILABLE;
		
		private var __currentFrameInfo:FrameInfo;
		
		public function AnimationRenderer(url:String, animationClass:String, scale:Number = 1.0, alpha:Number = 1.0)
		{
			this._url = url;
			this._animationClass = animationClass;
			
			resetAnimationCache(scale, alpha);
		}
		
		public function get cacheStrategy():uint
		{
			return this._cacheStrategy;
		}
		
		public function set cacheStrategy(value:uint):void
		{
			this._cacheStrategy = cacheStrategy;
		}
		
		public function set action(value:String):void
		{
			this._action = value;
		}
		
		public function get scale():Number
		{
			return _cache ? _cache.scale : 1.0;
		}
		
		public function set scale(value:Number):void
		{
			if (! this._cache || _cache.scale != value)
			{
				resetAnimationCache(value, this.alpha);
			}
		}
		
		public function get alpha():Number
		{
			return _cache ? _cache.alpha : 1.0;
		}
		
		public function set alpha(value:Number):void
		{
			if (! this._cache || _cache.alpha != value)
			{
				resetAnimationCache(this.scale, value);
			}
		}
		
		public function get currentOriginOffset():Point
		{
			return this.__currentFrameInfo ? __currentFrameInfo.offset : null;
		}
		
		public function get currentWidth():Number
		{
			return this.__currentFrameInfo ? __currentFrameInfo.bitmapData.width : 0;
		}
		
		public function get currentHeight():Number
		{
			return this.__currentFrameInfo ? __currentFrameInfo.bitmapData.height : 0;
		}
		
		public function nextFrame():Boolean
		{
			var endFlag:Boolean = true;
			
			if (this.status == AnimationRendererStatus.PLAYING)
			{
				if (this.__totalFrames == TOTAL_FRAMES_UNAVAILABLE)
				{
					this.__totalFrames = _cache.getTotalFramesForAction(this._action);		//尝试获取
				}
				
				if (this.__totalFrames != TOTAL_FRAMES_UNAVAILABLE)
				{
					if (++ this._currentFrame >= this.__totalFrames)
					{
						this._currentFrame = 0;
					}
					else
					{
						endFlag = false;
					}
				}
			}
			
			return endFlag;
		}
		
		public function paint(canvas:BitmapData, rect:Rectangle, x:Number, y:Number):void
		{
			this.__currentFrameInfo = _cache.getFrameForAction(this._currentFrame, this._action, this.cacheStrategy);		// __currentFrameInfo不能因为alpha为0而不更新
			
			if (_cache.alpha > 0 && this.__currentFrameInfo)					//alpha在这里处理，以保证任何时候 __currentFrameInfo都是最新的帧数据，从而保证其他方法有效
			{
				__PAINT_DECT_POINT.x = x + __currentFrameInfo.offset.x - rect.x;
				__PAINT_DECT_POINT.y = y + __currentFrameInfo.offset.y - rect.y;
				
				canvas.copyPixels(__currentFrameInfo.bitmapData, __currentFrameInfo.bitmapData.rect, __PAINT_DECT_POINT, null, null, true);
			}
		}
		
		public function hitTest(x:Number, y:Number):Boolean
		{
			if (this.__currentFrameInfo)
			{
				var bitmapData:BitmapData = __currentFrameInfo.bitmapData;
				
				x -= __currentFrameInfo.offset.x;
				y -= __currentFrameInfo.offset.y;
				
				if (x >= 0 && y >= 0 && x < bitmapData.width && y < bitmapData.height)
				{
					return (bitmapData.getPixel32(x, y) >>> 24) != 0;
				}
			}
			
			return false;
		}
		
		public function dispose():void
		{
			AnimationCacheManager.instance.releaseAnimationCache(this._cache);
		}
		
		private function resetAnimationCache(scale:Number, alpha:Number):void
		{
			this._cache && AnimationCacheManager.instance.releaseAnimationCache(this._cache);
			this._cache = AnimationCacheManager.instance.getAnimationCache(this._url, this._animationClass, scale, alpha);
			this.__currentFrameInfo = _cache.getFrameForAction(this._currentFrame, this._action, this.cacheStrategy);
		}
	}
}